package com.yxq.sso.controller;

import com.yxq.sso.Service.UserService;
import com.yxq.sso.Service.impl.SmsServiceImpl;
import com.yxq.sso.common.ExceptionCode;
import com.yxq.sso.common.JsonResult;
import com.yxq.sso.entity.ExamineApproval;
import com.yxq.sso.entity.MenuVo;
import com.yxq.sso.entity.Role;
import com.yxq.sso.entity.User;
import com.yxq.sso.exception.BusinessException;
import com.yxq.sso.repository.ExamineApprovalRepository;
import com.yxq.sso.repository.UserRepository;
import com.yxq.sso.util.JsonUtil;
import com.yxq.sso.util.MD5Util;
import com.yxq.sso.util.StringUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 用户执行一键登录或注册的接口
 *
 * @author YXQ
 * @date 2021/11/30 9:20
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    UserService userService;

    @Autowired
    UserRepository userRepository;

    @Autowired
    ExamineApprovalRepository examineApprovalRepository;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 设定盐值
     */
    public static final String SALT = "YXQ";

    /**
     * 注册的辅助Key
     */
    private static final String REG_SMS = "reg";

    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "loginType", value = "登录类型1.pc 2.小程序", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "code", value = "验证码", dataType = "string", paramType = "query")
    })
    @ApiOperation("手机号验证码登录")
    @GetMapping("/loginByCode")
    public Map<String, Object> loginByCode(String phone, Integer loginType, String code) throws BusinessException {
        // 先对用户的手机号做校验
        if (StringUtils.isEmpty(phone)) {
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_NOT_ALLOW_NULL);
        }
        if (!StringUtils.isPhoneNumber(phone)) {
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_IS_WRONG);
        }
        if (StringUtils.isEmpty(code)) {
            throw new BusinessException(ExceptionCode.CODE_NOT_ALLOW_NULL);
        }
        if (loginType == null) {
            throw new BusinessException(ExceptionCode.LOGIN_TYPE_NOT_ALLOW_NULL);
        }
        Map<String, Object> login = userService.login(phone, code, loginType);
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode("1");
        jsonResult.setMsg("登录成功");
        jsonResult.put("token", login.get("token"));
        jsonResult.put("menu", login.get("menu"));
        jsonResult.put("user", login.get("user"));
        return jsonResult.getDataMap();
    }

    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "loginType", value = "登录类型1.pc 2.小程序", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", dataType = "string", paramType = "query")
    })
    @ApiOperation("手机号密码登录")
    @GetMapping("/loginByPassword")
    public Map<String, Object> loginByPassword(String phone, Integer loginType, String password) throws BusinessException {
        // 先对用户的手机号做校验
        if (StringUtils.isEmpty(phone)) {
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_NOT_ALLOW_NULL);
        }
        if (!StringUtils.isPhoneNumber(phone)) {
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_IS_WRONG);
        }
        if (StringUtils.isEmpty(password)) {
            throw new BusinessException(ExceptionCode.PASSWORD_NOT_ALLOW_NULL);
        }
        if (loginType == null) {
            throw new BusinessException(ExceptionCode.LOGIN_TYPE_NOT_ALLOW_NULL);
        }
        Map<String, Object> login = userService.loginByPassword(phone, password, loginType);
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode("1");
        jsonResult.setMsg("登录成功");
        jsonResult.put("token", login.get("token"));
        jsonResult.put("menu", login.get("menu"));
        jsonResult.put("user", login.get("user"));
        return jsonResult.getDataMap();
    }

    @GetMapping("/authMenuTest")
    public Map<String, Object> authMenuTest(Long id) throws BusinessException {
        User user = new User();
        user.setId(id);
        List<MenuVo> userMenuVoTree = userService.getUserMenuVoTree(user);
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode("1");
        jsonResult.setMsg("登录成功");
        jsonResult.put("userMenuVoTree", userMenuVoTree);
        return jsonResult.getDataMap();
    }

    @ApiImplicitParam(name = "token", value = "token", dataType = "string", required = true, paramType = "query")
    @PostMapping("/queryUserByToken")
    @ApiOperation("服务器之间验证token")
    public User queryUserByToken(String token) throws BusinessException {
        return userService.queryUserByToken(token);
    }

    @GetMapping("/reg")
    @ApiOperation("用户的注册接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "roleId", value = "角色对应的id值1.普通2.普通管理3.高级管理", dataType = "long", paramType = "query"),
            @ApiImplicitParam(name = "code", value = "验证码", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "loginType", value = "登录类型", dataType = "int", paramType = "query")
    })
    public Map<String, Object> register(String phone, Long roleId, String code, Integer loginType) throws BusinessException {
        // 先对用户的手机号做校验
        if (StringUtils.isEmpty(phone)) {
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_NOT_ALLOW_NULL);
        }
        if (!StringUtils.isPhoneNumber(phone)) {
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_IS_WRONG);
        }
        // 注册，身份选错了，先注册成为了普通学员，再注册其他角色,即一个用户担任多种角色
        // 注册时，先判断用户是否注册，如果注册过，判断是否是注册其他
        User byPhoneEquals = userRepository.findByPhoneEquals(phone);

        // 1.获取redis服务器存储的验证码
        ValueOperations<String, Object> stringOps = redisTemplate.opsForValue();
        Object o = stringOps.get(SmsServiceImpl.LOGIN_SMS + phone);
        // 验证码失效的判断,如果为空则抛出异常
        if (o == null) {
            // 帐号或短信验证码错误，请重新输入
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_OR_CODE_FAILED);
        }
        // 转化验证码为字符串
        String redisCode = o.toString();
        // 对验证码做校验, 如果不一致则抛出异常
        if (!redisCode.equals(code)) {
            // 帐号或短信验证码错误，请重新输入
            throw new BusinessException(ExceptionCode.PHONE_NUMBER_OR_CODE_FAILED);
        }
        // 删除验证码,防止验证码被多次使用
        redisTemplate.delete(SmsServiceImpl.LOGIN_SMS + phone);
        // 如果用户不存在开始注册
        if (byPhoneEquals == null) {
            // 开始注册--普通用户直接注册
            User newUser = new User();
            // 设置默认的用户名
            newUser.setName("用户" + phone);
            // 设置用户的手机号
            newUser.setPhone(phone);
            // 设置用户的密码盐值
            newUser.setSalt(SALT);
            // 截取手机号后六位作为密码
            String substring = phone.substring(5);
            // 手机号后六位加盐然后加密
            String encode = MD5Util.encode(substring + SALT);
            // 设置用户初始密码
            newUser.setPassword(encode);
            // 设置用户的状态为正常
            newUser.setStatus(1);
            // 设置登录状态
            newUser.setLoginType(loginType);
            // 如果注册的是其他管理员需要被审核
            // 创建一个审批流程
            ExamineApproval examineApproval = new ExamineApproval();
            // 设置审批流程的类型是 申请管理员
            examineApproval.setType("申请管理员");
            // 系统当前时间
            Date date = new Date();
            // 设置这个审批流程的创建时间为当前时间
            examineApproval.setCreationTime(date);
            // 设置这个审批流程的审批状态为审批中
            examineApproval.setState(0);
            // 设置这个审批流程的意见征询节点为1(只能由超级管理员同意成为各种角色)
            examineApproval.setOpinion(1);
            // 其他角色注册时默认先成为普通用户
            // 如果是添加普通用户直接注册
            // 注册成为普通用户
            userRepository.save(newUser);
            // 获取用户的id
            Long id = newUser.getId();
            // 在用户角色表中关联角色的id值以及
            userService.setUserRole(id, 3L);
            if (roleId.equals(2L)) {
                // 设置这个审批流程的名字
                examineApproval.setName("创建普通管理员" + phone);
                // 设置上传人
                examineApproval.setUserId(id);
                // 如果存在这个流程且未过截止日期，抛出请等待审核，24小时后才能再次提交
                ExamineApproval byNameEquals = examineApprovalRepository.findByNameEquals(examineApproval.getName());
                // 设置审批流程的备注
                examineApproval.setExplain(id + "注册成为普通管理员2");
                // 存在这个流程
                if (byNameEquals != null) {
                    // 获取系统记录中的截止日期
                    Date expirationDate = byNameEquals.getExpirationDate();
                    // 判断截止时间是否大于当前时间
                    if (expirationDate.after(date)) {
                        throw new BusinessException(ExceptionCode.PLEASE_SUBMIT_AGAIN);
                    } else {
                        // 获取当前时间下一天的日期
                        Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                        // 设置截止日期
                        examineApproval.setExpirationDate(nextDay);
                        // 更新截止日期到审批管理中
                        examineApprovalRepository.save(byNameEquals);
                        // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                        throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                    }
                } else {
                    // 获取当前时间下一天的日期
                    Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                    // 设置截止日期
                    examineApproval.setExpirationDate(nextDay);
                    // 添加到审批管理中
                    examineApprovalRepository.save(examineApproval);
                    // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                    throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                }
            }// 如果是添加高级管理员
            else if (roleId.equals(3L)) {
                // 设置这个审批流程的名字
                examineApproval.setName("创建高级管理员" + phone);
                // 设置上传人
                examineApproval.setUserId(id);
                // 如果存在这个流程且未过截止日期，抛出请等待审核，24小时后才能再次提交
                ExamineApproval byNameEquals = examineApprovalRepository.findByNameEquals(examineApproval.getName());
                // 设置审批流程的备注
                examineApproval.setExplain(id + "注册成为高级管理员1");
                // 存在这个流程
                if (byNameEquals != null) {
                    // 获取系统记录中的截止日期
                    Date expirationDate = byNameEquals.getExpirationDate();
                    // 判断截止时间是否大于当前时间
                    if (expirationDate.after(date)) {
                        // 您已经提交过了，请不要重复提交,在24小时之后,才能再次提交
                        throw new BusinessException(ExceptionCode.PLEASE_SUBMIT_AGAIN);
                    } else {
                        // 获取当前时间下一天的日期
                        Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                        // 设置截止日期
                        examineApproval.setExpirationDate(nextDay);
                        // 更新截止日期到审批管理中
                        examineApprovalRepository.save(byNameEquals);
                        // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                        throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                    }
                } else {
                    // 获取当前时间下一天的日期
                    Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                    // 设置截止日期
                    examineApproval.setExpirationDate(nextDay);
                    // 添加到审批管理中
                    examineApprovalRepository.save(examineApproval);
                    // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                    throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                }
            }
        } else {
            Long id = byPhoneEquals.getId();
            // 查看当前用户拥有的角色
            List<Role> userRole = userService.findUserRole(id);
            // 遍历当前用户拥有的角色
            for (Role role : userRole) {
                // 如果当前用户的角色和待注册的角色的id值相同
                if (role.getId().equals(roleId)) {
                    // 您的当前手机号已经注册过了,建议您直接去登录
                    throw new BusinessException(ExceptionCode.ALREADY_IS_ROLE);
                }
            }
            // 如果是注册成为其他角色
            // 创建一个审批流程
            ExamineApproval examineApproval = new ExamineApproval();
            // 设置审批流程的类型是添加角色
            examineApproval.setType("申请管理员");
            // 系统当前时间
            Date date = new Date();
            // 设置这个审批流程的创建时间为当前时间
            examineApproval.setCreationTime(date);
            // 设置这个审批流程的审批状态为审批中
            examineApproval.setState(0);
            // 设置这个审批流程的意见征询节点为1(只能由超级管理员同意成为各种角色)
            examineApproval.setOpinion(1);
            if (roleId.equals(2L)) {
                // 设置这个审批流程的名字
                examineApproval.setName("创建普通管理员" + phone);
                // 设置上传人
                examineApproval.setUserId(id);
                // 如果存在这个流程且未过截止日期，抛出请等待审核，24小时后才能再次提交
                ExamineApproval byNameEquals = examineApprovalRepository.findByNameEquals(examineApproval.getName());
                // 存在这个流程
                if (byNameEquals != null) {
                    // 获取系统记录中的截止日期
                    Date expirationDate = byNameEquals.getExpirationDate();
                    // 判断截止时间是否大于当前时间
                    if (expirationDate.after(date)) {
                        throw new BusinessException(ExceptionCode.PLEASE_SUBMIT_AGAIN);
                    } else {
                        // 获取当前时间下一天的日期
                        Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                        // 设置截止日期
                        examineApproval.setExpirationDate(nextDay);
                        // 更新截止日期到审批管理中
                        examineApprovalRepository.save(byNameEquals);
                        // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                        throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                    }
                } else {
                    // 获取当前时间下一天的日期
                    Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                    // 设置截止日期
                    examineApproval.setExpirationDate(nextDay);
                    // 添加到审批管理中
                    examineApprovalRepository.save(examineApproval);
                    // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                    throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                }
            }// 如果是添加高级管理员
            else if (roleId.equals(3L)) {
                // 设置这个审批流程的名字
                examineApproval.setName("创建高级管理员" + phone);
                // 设置上传人
                examineApproval.setUserId(id);
                // 如果存在这个流程且未过截止日期，抛出请等待审核，24小时后才能再次提交
                ExamineApproval byNameEquals = examineApprovalRepository.findByNameEquals(examineApproval.getName());
                // 存在这个流程
                if (byNameEquals != null) {
                    // 获取系统记录中的截止日期
                    Date expirationDate = byNameEquals.getExpirationDate();
                    // 判断截止时间是否大于当前时间
                    if (expirationDate.after(date)) {
                        // 您已经提交过了，请不要重复提交,在24小时之后,才能再次提交
                        throw new BusinessException(ExceptionCode.PLEASE_SUBMIT_AGAIN);
                    } else {
                        // 获取当前时间下一天的日期
                        Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                        // 设置截止日期
                        examineApproval.setExpirationDate(nextDay);
                        // 更新截止日期到审批管理中
                        examineApprovalRepository.save(byNameEquals);
                        // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                        throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                    }
                } else {
                    // 获取当前时间下一天的日期
                    Date nextDay = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
                    // 设置截止日期
                    examineApproval.setExpirationDate(nextDay);
                    // 添加到审批管理中
                    examineApprovalRepository.save(examineApproval);
                    // 提交审核成功,请等待管理员审核(24小时之后,未成功,才能再次提交)
                    throw new BusinessException(ExceptionCode.REGISTER_SUCCESS_BUT_EXAMINE);
                }
            }
        }
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode("1");
        jsonResult.setMsg("注册成功，请等待管理员审批，或者去登录试试吧");
        return jsonResult.getDataMap();
    }
}
